#include <string.h>
#include "tst/test_frame.h"
#include "tst/bas/test_container_utility.h"
#include "bas/bas_vector.h"

int tst_basVectorCreate_simple(void)
{
    T_Vector *ptVector = basVectorCreate(_T(T_TestSimpleStruct));

    TEST_ASSERT(ptVector != NULL);
    TEST_ASSERT(ptVector->tTypeInfo.nTypeSize == sizeof(T_TestSimpleStruct));
    TEST_ASSERT(NULL == ptVector->tTypeInfo.pfnDestroy);
    TEST_ASSERT(NULL == ptVector->tTypeInfo.pfnCopy);
    TEST_ASSERT(NULL == ptVector->tTypeInfo.pfnLess);
    TEST_ASSERT(NULL == ptVector->tTypeInfo.pfnInit);
    TEST_ASSERT(ptVector->ptCallBackTable != NULL);
    TEST_ASSERT(ptVector->pvStartPos == ptVector->pvEndPos)
    TEST_ASSERT(ptVector->pvEndPosOfStorage == ptVector->pvStartPos + VECTOR_INIT_SIZE * sizeof(T_TestSimpleStruct));

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVectorCreate_complexOnlyDestroyCopy(void)
{
    T_Vector *ptVector = basVectorCreate(_T(T_TestComplexStruct, testComplexStructDestroy, testComplexStructCopy));

    TEST_ASSERT(ptVector != NULL);
    TEST_ASSERT(ptVector->tTypeInfo.nTypeSize == sizeof(T_TestComplexStruct));
    TEST_ASSERT((T_DestroyFunction)testComplexStructDestroy == ptVector->tTypeInfo.pfnDestroy);
    TEST_ASSERT((T_CopyFunction)testComplexStructCopy == ptVector->tTypeInfo.pfnCopy);
    TEST_ASSERT(NULL == ptVector->tTypeInfo.pfnLess);
    TEST_ASSERT(NULL == ptVector->tTypeInfo.pfnInit);
    TEST_ASSERT(ptVector->pvStartPos == ptVector->pvEndPos)
    TEST_ASSERT(ptVector->pvEndPosOfStorage == ptVector->pvStartPos + VECTOR_INIT_SIZE * sizeof(T_TestComplexStruct));

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVectorCreate_complex(void)
{
    T_Vector *ptVector = basVectorCreate(_T(T_TestComplexStruct,
                                            testComplexStructDestroy, testComplexStructCopy,
                                            testComplexStructLess, testComplexStructInit));
    TEST_ASSERT(ptVector != NULL)
    TEST_ASSERT(ptVector->tTypeInfo.nTypeSize == sizeof(T_TestComplexStruct));
    TEST_ASSERT((T_DestroyFunction)testComplexStructDestroy == ptVector->tTypeInfo.pfnDestroy);
    TEST_ASSERT((T_CopyFunction)testComplexStructCopy == ptVector->tTypeInfo.pfnCopy);
    TEST_ASSERT((T_CompareFunction)testComplexStructLess == ptVector->tTypeInfo.pfnLess);
    TEST_ASSERT((T_InitFunction)testComplexStructInit == ptVector->tTypeInfo.pfnInit);
    TEST_ASSERT(ptVector->pvStartPos == ptVector->pvEndPos)
    TEST_ASSERT(ptVector->pvEndPosOfStorage == ptVector->pvStartPos + VECTOR_INIT_SIZE * sizeof(T_TestComplexStruct));

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVectorPushBack_simple(void)
{
    T_Vector *ptVector = NULL;
    T_TestSimpleStruct tTestSimpleStruct;

    ptVector = basVectorCreate(_T(T_TestSimpleStruct));
    TEST_ASSERT(ptVector != NULL)

    for (int i = 0; i < 1000000; ++i)
    {
        memset(&tTestSimpleStruct, 0, sizeof(T_TestSimpleStruct));
        tTestSimpleStruct.i = i;
        tTestSimpleStruct.f = (float)(i + 1);
        TEST_ASSERT(basVectorPushBack(ptVector, &tTestSimpleStruct) == 0);
    }

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVectorAt(void)
{
    T_Vector *ptVector = NULL;
    T_TestSimpleStruct tTestSimpleStruct;
    
    ptVector = basVectorCreate(_T(T_TestSimpleStruct));
    TEST_ASSERT(ptVector != NULL);

    for (int i = 0; i < 1000; ++i)
    {
        memset(&tTestSimpleStruct, 0, sizeof(T_TestSimpleStruct));
        tTestSimpleStruct.i = i;

        TEST_ASSERT(basVectorPushBack(ptVector, &tTestSimpleStruct) == 0);
    }

    TEST_ASSERT(0 == ((T_TestSimpleStruct *)basVectorAt(ptVector, 0))->i);
    TEST_ASSERT(999 == ((T_TestSimpleStruct *)basVectorAt(ptVector, 999))->i);
    TEST_ASSERT(999 == ((T_TestSimpleStruct *)basVectorAt(ptVector, 1000))->i);
    TEST_ASSERT(999 == ((T_TestSimpleStruct *)basVectorAt(ptVector, 10000))->i);
    TEST_ASSERT(999 == ((T_TestSimpleStruct *)basVectorAt(ptVector, -1))->i);
    TEST_ASSERT(998 == ((T_TestSimpleStruct *)basVectorAt(ptVector, -2))->i);
    TEST_ASSERT(1 == ((T_TestSimpleStruct *)basVectorAt(ptVector, -999))->i);
    TEST_ASSERT(0 == ((T_TestSimpleStruct *)basVectorAt(ptVector, -1000))->i);
    TEST_ASSERT(0 == ((T_TestSimpleStruct *)basVectorAt(ptVector, -1001))->i);
    TEST_ASSERT(0 == ((T_TestSimpleStruct *)basVectorAt(ptVector, -10000))->i);

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVectorPopBack(void)
{
    T_Vector *ptVector = NULL;    
    T_TestComplexStruct tTestComplexStruct;

    ptVector = basVectorCreate(_T(T_TestComplexStruct, testComplexStructDestroy, testComplexStructCopy));
    TEST_ASSERT(ptVector != NULL)

    for (int j = 0; j < 100; ++j)
    {
        for (int i = 0; i < 10000; ++i) 
        {
            memset(&tTestComplexStruct, 0, sizeof(T_TestComplexStruct));
            tTestComplexStruct.i = i;
            tTestComplexStruct.ptData = (T_TestSimpleStruct *)malloc(sizeof(T_TestSimpleStruct));
            TEST_ASSERT(basVectorPushBack(ptVector, &tTestComplexStruct) == 0);
            free(tTestComplexStruct.ptData);
        }

        for (int i = 0; i < 5000; ++i)
        {
            basVectorPopBack(ptVector);
        }
        TEST_ASSERT(5000 == basVectorSize(ptVector), "FAILED IN LOOP[%d]\n", j);
        TEST_ASSERT(4999 == ((T_TestComplexStruct *)basVectorAt(ptVector, -1))->i, 
                    "FAILED IN LOOP[%d]\n", j);

        for (int i = 5000; i < 10000; ++i)
        {
            basVectorPopBack(ptVector);
        }
        TEST_ASSERT(basVectorEmpty(ptVector), "FAILED IN LOOP[%d]\n", j);
    }

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVectorResize_remove(void)
{
    T_Vector *ptVector = NULL;
    T_TestComplexStruct tTestComplexStruct;

    ptVector = basVectorCreate(_T(T_TestComplexStruct, 
                                  testComplexStructDestroy, testComplexStructCopy,
                                  testComplexStructLess, testComplexStructInit));
    TEST_ASSERT(ptVector != NULL);

    for (int j = 0; j < 100; ++j)
    {
        for (int i = 0; i < 10000; ++i)
        {
            memset(&tTestComplexStruct, 0, sizeof(T_TestComplexStruct));
            tTestComplexStruct.i = i;
            tTestComplexStruct.ptData = (T_TestSimpleStruct *)malloc(sizeof(T_TestSimpleStruct));
            TEST_ASSERT(basVectorPushBack(ptVector, &tTestComplexStruct) == 0);
            free(tTestComplexStruct.ptData);
        }
        TEST_ASSERT(basVectorResize(ptVector, 0) == 0);
        TEST_ASSERT(basVectorEmpty(ptVector));
    }

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVectorResize_add(void)
{
    T_Vector *ptVector = NULL;

    ptVector = basVectorCreate(_T(T_TestComplexStruct, 
                                  testComplexStructDestroy, testComplexStructCopy,
                                  testComplexStructLess, testComplexStructInit));
    TEST_ASSERT(ptVector != NULL);

    for (int i = 100; i < 10000; i += 100)
    {
        TEST_ASSERT(basVectorResize(ptVector, i) == 0); 
        TEST_ASSERT(basVectorSize(ptVector) == i);
        TEST_ASSERT(((T_TestComplexStruct *)basVectorAt(ptVector, -1))->i == 1);
        TEST_ASSERT(basVectorCapacity(ptVector) == i);
    }

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVectorDestroy(void)
{
    T_Vector *ptVector = NULL;

    for (int i = 0; i < 100000; ++i)
    {
        ptVector = basVectorCreate(_T(T_TestComplexStruct, 
                                      testComplexStructDestroy, testComplexStructCopy,
                                      testComplexStructLess, testComplexStructInit));
        TEST_ASSERT(ptVector != NULL);
        basVectorDestroy(ptVector);
    }

    return 0;
}

int tst_basVectorIterator(void)
{
    T_Vector *ptVector = NULL;
    T_TestSimpleStruct tTestSimpleStruct;
    int iCount = 0; 

    ptVector = basVectorCreate(_T(T_TestSimpleStruct));
    TEST_ASSERT(ptVector != NULL)

    for (int i = 0; i < 100000; ++i)
    {
        memset(&tTestSimpleStruct, 0, sizeof(T_TestSimpleStruct));
        tTestSimpleStruct.i = i;
        tTestSimpleStruct.f = (float)(i + 1);
        TEST_ASSERT(basVectorPushBack(ptVector, &tTestSimpleStruct) == 0);
    }

    //正向迭代
    for (T_Iterator tIterator = basVectorBegin(ptVector);
         !basIteratorEqual(tIterator, basVectorEnd(ptVector));
         tIterator = basIteratorNext(tIterator))
    {
        TEST_ASSERT(BAS_ITER_GET_FIELD(tIterator, T_TestSimpleStruct, i) == iCount++);
    }

    //反向迭代
    for (T_Iterator tIterator = basVectorRBegin(ptVector);
         !basIteratorEqual(tIterator, basVectorREnd(ptVector));
         tIterator = basIteratorPrev(tIterator))
    {
        TEST_ASSERT(BAS_ITER_GET_FIELD(tIterator, T_TestSimpleStruct, i) == --iCount);
    }

    TEST_ASSERT(basIteratorEqual(basIteratorNextN(basVectorBegin(ptVector), 100000), basVectorEnd(ptVector)));
    TEST_ASSERT(basIteratorEqual(basIteratorPrevN(basVectorRBegin(ptVector), 100000), basVectorREnd(ptVector)));
    TEST_ASSERT(basIteratorMinus(basVectorBegin(ptVector), basVectorEnd(ptVector)) == -100000);
    TEST_ASSERT(basIteratorMinus(basVectorEnd(ptVector), basVectorBegin(ptVector)) == 100000);
    TEST_ASSERT(basIteratorMinus(basVectorRBegin(ptVector), basVectorREnd(ptVector)) == 100000);
    TEST_ASSERT(basIteratorMinus(basVectorREnd(ptVector), basVectorRBegin(ptVector)) == -100000);

    basVectorDestroy(ptVector);
        
    return 0;
}

int tst_basVectorInsert(void)
{
    T_Vector *ptVector = NULL;
    T_TestSimpleStruct tTestSimpleStruct;
    
    ptVector = basVectorCreate(_T(T_TestSimpleStruct));
    TEST_ASSERT(ptVector != NULL);

    for (int i = 0; i < 100000; ++i)
    {
        memset(&tTestSimpleStruct, 0, sizeof(T_TestSimpleStruct));
        tTestSimpleStruct.i = i;
        TEST_ASSERT(basIteratorIsValid(basVectorInsert(ptVector, basVectorEnd(ptVector), &tTestSimpleStruct)));
    }

    T_Iterator tIterator = basVectorBegin(ptVector);
    for (int i = 0; i < 50000; ++i)
        tIterator = basIteratorNext(tIterator);

    memset(&tTestSimpleStruct, 0, sizeof(T_TestSimpleStruct));
    tTestSimpleStruct.f = 1;

    TEST_ASSERT(basIteratorIsValid(tIterator = basVectorInsert(ptVector, tIterator, &tTestSimpleStruct)));
    TEST_ASSERT(1 == ((T_TestSimpleStruct *)basVectorAt(ptVector, 50000))->f);
    TEST_ASSERT(0 == ((T_TestSimpleStruct *)basVectorAt(ptVector, 50000))->i);
    TEST_ASSERT(0 == ((T_TestSimpleStruct *)basVectorAt(ptVector, 50001))->f);
    TEST_ASSERT(50000 == ((T_TestSimpleStruct *)basVectorAt(ptVector, 50001))->i);

    basVectorDestroy(ptVector);
         
    return 0;
}

int tst_basVectorErase(void)
{
    T_Vector *ptVector = NULL;
    T_TestSimpleStruct tTestSimpleStruct;
    
    ptVector = basVectorCreate(_T(T_TestSimpleStruct));
    TEST_ASSERT(ptVector != NULL);

    for (int i = 0; i < 10000; ++i)
    {
        memset(&tTestSimpleStruct, 0, sizeof(T_TestSimpleStruct));
        tTestSimpleStruct.i = i;
        tTestSimpleStruct.f = (float)(i + 1);
        TEST_ASSERT(basVectorPushBack(ptVector, &tTestSimpleStruct) == 0);
    }

    for (int i = 0; i < 10000; ++i)
    {
        basVectorErase(ptVector, basVectorBegin(ptVector));
    }

    TEST_ASSERT(basVectorEmpty(ptVector));

    basVectorDestroy(ptVector);

    return 0;
}

int tst_basVector_bulidin_type(void)
{
    T_Vector *ptVector = NULL;

    TEST_ASSERT((ptVector = basVectorCreate(_T(BUILDIN_STRING))) != NULL);
    for (int i = 0; i < 100; ++i)
    {
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(basVectorPushBack(ptVector, "Hello,World!") == 0);
        }
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(strcmp("Hello,World!", *(char **)basVectorAt(ptVector, j)) == 0);
        }
        for (T_Iterator tIterator = basVectorBegin(ptVector);
             !basIteratorEqual(tIterator, basVectorEnd(ptVector));
             tIterator = basIteratorNext(tIterator))
        {
            TEST_ASSERT(strcmp("Hello,World!", *(char **)basIteratorGetPointer(tIterator)) == 0);
        }
        basVectorClear(ptVector);

        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(basIteratorIsValid(basVectorInsert(ptVector, basVectorEnd(ptVector), "Holy!")));
        }
        for (T_Iterator tIterator = basVectorBegin(ptVector);
             !basIteratorEqual(tIterator, basVectorEnd(ptVector));
             tIterator = basIteratorNext(tIterator))
        {
            TEST_ASSERT(strcmp("Holy!", *(char **)basIteratorGetPointer(tIterator)) == 0);
        }
        basVectorClear(ptVector);
        TEST_ASSERT(basVectorEmpty(ptVector));
    }
    basVectorDestroy(ptVector);

    TEST_ASSERT((ptVector = basVectorCreate(_T(BUILDIN_INT))) != NULL);
    for (int i = 0; i < 100; ++i)
    {
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(basVectorPushBack(ptVector, 123) == 0)
        }
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(123 == *(int *)basVectorAt(ptVector, j));
        }
        basVectorResize(ptVector, 0);
        TEST_ASSERT(basVectorEmpty(ptVector));
    }
    basVectorDestroy(ptVector);

    TEST_ASSERT((ptVector = basVectorCreate(_T(BUILDIN_LONG))) != NULL)
    for (int i = 0; i < 100; ++i)
    {
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(basVectorPushBack(ptVector, 12345L) == 0)
        }
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(12345L == *(long *)basVectorAt(ptVector, j));
        }
        basVectorResize(ptVector, 0);
        TEST_ASSERT(basVectorEmpty(ptVector));
    }
    basVectorDestroy(ptVector);

    TEST_ASSERT((ptVector = basVectorCreate(_T(BUILDIN_BOOL))) != NULL)
    for (int i = 0; i < 100; ++i)
    {
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(basVectorPushBack(ptVector, true) == 0)
        }
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(true == *(bool *)basVectorAt(ptVector, j));
        }
        basVectorResize(ptVector, 0);
        TEST_ASSERT(basVectorEmpty(ptVector));
    }
    basVectorDestroy(ptVector);

    TEST_ASSERT((ptVector = basVectorCreate(_T(BUILDIN_CHAR))) != NULL)
    for (int i = 0; i < 100; ++i)
    {
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT(basVectorPushBack(ptVector, 'K') == 0)
        }
        for (int j = 0; j < 10000; ++j)
        {
            TEST_ASSERT('K' == *(char *)basVectorAt(ptVector, j));
        }
        basVectorResize(ptVector, 0);
        TEST_ASSERT(basVectorEmpty(ptVector));
    }
    basVectorDestroy(ptVector);

    return 0;
}
